#ifndef VEHICLE_H
#define VEHICLE_H

#include <QList>
#include <QTime>
#include <QString>

#include "point.h"
class Driver;

using namespace GeometryUtilities;

class VehicleType
{
public:
  QString name;
  QString graphic;
  qreal wheelBase;
  qreal mass;
  qreal dragConstant;
  qreal maxEngineForce;
};

class Vehicle
{
public:
  enum DriverCommandEnum
  {
    DRIVE_ACCELERATE,
    DRIVE_BRAKE,
    DRIVE_STEER
  };

  struct DriverCommand
  {
    DriverCommandEnum cmd;
    qreal value;
    QTime time;
  };

  Vehicle(const QString &name, VehicleType *type=0);
  void tick();

  void setName(const QString &value);
  QString name();

  void setType(VehicleType *type);
  VehicleType* type();

  void setAcceleration(const Point &value);
  Point acceleration();

  void setVelocity(const Point &value);
  Point velocity();

  void setPosition(const Point &value);
  Point position();


  //qreal direction();
  void setDirection(const qreal angle);
  void setDirection(const Point &value);
  Point direction();

  void setMaxTurnRate(const qreal value);
  qreal maxTurnRate();

  void setMaxAcceleration(const qreal value);
  qreal maxAcceleration();

  void setMaxBrake(const qreal value);
  qreal maxBrake();

  void setWheelBase(const qreal value);
  qreal wheelBase();

  void setMass(const qreal value);
  qreal mass();

  void setDragConstant(const qreal value);
  qreal dragConstant();

  void setMaxEngineForce(const qreal value);
  qreal maxEngineForce();

  qreal travelDistance( bool inMiles = false );
  qreal speed( bool inMPH = false );
  qreal timeUntilSpeed(const qreal speedMPH = 0.0);
  qreal distUntilSpeed(const qreal speedMPH = 0.0);
  void actuators(qreal &acl, qreal &brake, qreal &steer);
  void forces(Point &engine, Point &brake, Point &friction, Point &drag);

  // Driver controls. These functions will act on vehicle
  // vectors based on behaviors of the driver.
  // They are not descrete SET functions like the above.

  Driver* driver();
  void setDriver(Driver* d);

  // Represents steering wheel. 0 = no adjustment,
  // -1 = steer max left, 1 = steer max right.
  // Changes vehicle direction.
  //
  //   . 0 .
  // -1     1
  void steer(qreal value);

  // Represents brake pedal. 0=no brake, 1=full brake.
  void brake(qreal value);

  // Represents gas pedal. 0=no gas (cruising), 1=full gas.
  void accelerate(qreal value);

  // List of commands issued by driver
  void command(const DriverCommand &cmd);

private:

  //based on the commands of the driver calculates the current acceleration of the vehicle
  void updateAcceleration();

  //based on the acceleration calculates the velocity of the vehicle
  void updateVelocity();

  //updates the heading of the vehicle based on the driver input
  void updateHeading();

  //updates the position of the vehicle using the current speed and heading
  void updatePosition();

  //update the force values to compute basic vehicle kinematics
  void updateForces();

  Point mPosition;          // in feet x feet
  Point mVelocity;          // in meters/sec
  Point mAcceleration;      // in meters/sec^2
  Point mDirection;         // in degrees -180..180
  qreal mMaxTurnRate;
  qreal mMaxAcceleration;   // in meters/sec^2
  qreal mMaxEngineForce;    // in (kg*m/sec^2) newtons
  qreal mMaxBrake;          // in (kg*m/sec^2) newtons
  qreal mMaxSpeed;          // in meters/sec
  qreal mPrevAccelerate;
  qreal mGoalSpeed;         // in meters/sec
  qreal mOdometer;
  float mMass;              // in kilograms
  float mWheelBase;         // in feet
  Point mEngineForce;       // in (kg*m/sec^2) newtons
  Point mDragForce;         // in (kg*m/sec^2) newtons
  Point mBrakeForce;        // in (kg*m/sec^2) newtons
  Point mFrictionForce;     // in (kg*m/sec^2) newtons
  float mSteerAngle;
  float mDragConstant;
  bool  mBraking;

  qreal mBrakeVal;
  qreal mAccelVal;


  QString mName;
  VehicleType *mType;
  QList<DriverCommand> mCommands;
  Driver *mDriver;
};

#endif // VEHICLE_H
